home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Python 1.4 / Python 1.4 source / Mac / scripts / EditPythonPrefs.py < prev    next >
Encoding:
Python Source  |  1996-10-22  |  11.4 KB  |  445 lines  |  [TEXT/Pyth]

  1. """Edit the Python Preferences file."""
  2. #
  3. # This program is getting more and more clunky. It should really
  4. # be rewritten in a modeless way some time soon.
  5.  
  6. from Dlg import *
  7. from Events import *
  8. from Res import *
  9. import string
  10. import struct
  11. import macfs
  12. import MacOS
  13. import os
  14. import sys
  15. import Res # For Res.Error
  16.  
  17. # Resource in the Python resource chain
  18. PREFNAME_NAME="PythonPreferenceFileName"
  19.  
  20. # resource IDs in our own resources (dialogs, etc)
  21. MESSAGE_ID = 256
  22.  
  23. DIALOG_ID = 511
  24. TEXT_ITEM = 1
  25. OK_ITEM = 2
  26. CANCEL_ITEM = 3
  27. DIR_ITEM = 4
  28. TITLE_ITEM = 5
  29. OPTIONS_ITEM = 7
  30.  
  31. # The options dialog. There is a correspondence between
  32. # the dialog item numbers and the option.
  33. OPT_DIALOG_ID = 510
  34. # 1 thru 9 are the options
  35. # The GUSI creator/type and delay-console
  36. OD_CREATOR_ITEM = 10
  37. OD_TYPE_ITEM = 11
  38. OD_DELAYCONSOLE_ITEM = 12
  39. OD_OK_ITEM = 13
  40. OD_CANCEL_ITEM = 14
  41.  
  42. # Resource IDs in the preferences file
  43. PATH_STRINGS_ID = 128
  44. DIRECTORY_ID = 128
  45. OPTIONS_ID = 128
  46. GUSI_ID = 10240
  47.  
  48. # Override IDs (in the applet)
  49. OVERRIDE_PATH_STRINGS_ID = 129
  50. OVERRIDE_DIRECTORY_ID = 129
  51. OVERRIDE_OPTIONS_ID = 129
  52. OVERRIDE_GUSI_ID = 10241
  53.  
  54. # Things we know about the GUSI resource. Note the code knows these too.
  55. GUSIPOS_TYPE=0
  56. GUSIPOS_CREATOR=4
  57. GUSIPOS_SKIP=8
  58. GUSIPOS_FLAGS=9
  59. GUSIPOS_VERSION=10
  60. GUSIVERSION='0181'
  61. GUSIFLAGS_DELAY=0x20 # Mask
  62.  
  63. READ = 1
  64. WRITE = 2
  65. smAllScripts = -3
  66. kOnSystemDisk = 0x8000
  67.  
  68. def restolist(data):
  69.     """Convert STR# resource data to a list of strings"""
  70.     if not data:
  71.         return []
  72.     num, = struct.unpack('h', data[:2])
  73.     data = data[2:]
  74.     rv = []
  75.     for i in range(num):
  76.         strlen = ord(data[0])
  77.         if strlen < 0: strlen = strlen + 256
  78.         str = data[1:strlen+1]
  79.         data = data[strlen+1:]
  80.         rv.append(str)
  81.     return rv
  82.     
  83. def listtores(list):
  84.     """Convert a list of strings to STR# resource data"""
  85.     rv = struct.pack('h', len(list))
  86.     for str in list:
  87.         rv = rv + chr(len(str)) + str
  88.     return rv
  89.  
  90. def message(str = "Hello, world!", id = MESSAGE_ID):
  91.     """Show a simple alert with a text message"""
  92.     d = GetNewDialog(id, -1)
  93.     d.SetDialogDefaultItem(1)
  94.     tp, h, rect = d.GetDialogItem(2)
  95.     SetDialogItemText(h, str)
  96.     while 1:
  97.         n = ModalDialog(None)
  98.         if n == 1: break
  99.         
  100. def optinteract((options, creator, type, delaycons)):
  101.     """Let the user interact with the options dialog"""
  102.     old_options = (options[:], creator, type, delaycons)
  103.     d = GetNewDialog(OPT_DIALOG_ID, -1)
  104.     tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
  105.     SetDialogItemText(h, creator)
  106.     tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
  107.     SetDialogItemText(h, type)
  108.     d.SetDialogDefaultItem(OD_OK_ITEM)
  109.     d.SetDialogCancelItem(OD_CANCEL_ITEM)
  110.     while 1:
  111.         for i in range(len(options)):
  112.             tp, h, rect = d.GetDialogItem(i+1)
  113.             h.as_Control().SetControlValue(options[i])
  114.         tp, h, rect = d.GetDialogItem(OD_DELAYCONSOLE_ITEM)
  115.         h.as_Control().SetControlValue(delaycons)
  116.         n = ModalDialog(None)
  117.         if n == OD_OK_ITEM:
  118.             tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
  119.             ncreator = GetDialogItemText(h)
  120.             tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
  121.             ntype = GetDialogItemText(h)
  122.             if len(ncreator) == 4 and len(ntype) == 4:
  123.                 return options, ncreator, ntype, delaycons
  124.             else:
  125.                 sys.stderr.write('\007')
  126.         elif n == OD_CANCEL_ITEM:
  127.             return old_options
  128.         elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM):
  129.             pass
  130.         elif n == OD_DELAYCONSOLE_ITEM:
  131.             delaycons = (not delaycons)
  132.         elif 1 <= n <= len(options):
  133.             options[n-1] = (not options[n-1])
  134.  
  135.             
  136. def interact(list, pythondir, options, title):
  137.     """Let the user interact with the dialog"""
  138.     opythondir = pythondir
  139.     try:
  140.         # Try to go to the "correct" dir for GetDirectory
  141.         os.chdir(pythondir.as_pathname())
  142.     except os.error:
  143.         pass
  144.     d = GetNewDialog(DIALOG_ID, -1)
  145.     tp, h, rect = d.GetDialogItem(TITLE_ITEM)
  146.     SetDialogItemText(h, title)
  147.     tp, h, rect = d.GetDialogItem(TEXT_ITEM)
  148.     SetDialogItemText(h, string.joinfields(list, '\r'))
  149. ##    d.SetDialogDefaultItem(OK_ITEM)
  150.     d.SetDialogCancelItem(CANCEL_ITEM)
  151.     while 1:
  152.         n = ModalDialog(None)
  153.         if n == OK_ITEM:
  154.             break
  155.         if n == CANCEL_ITEM:
  156.             return None
  157. ##        if n == REVERT_ITEM:
  158. ##            return [], pythondir
  159.         if n == DIR_ITEM:
  160.             fss, ok = macfs.GetDirectory('Select python home folder:')
  161.             if ok:
  162.                 pythondir = fss
  163.         if n == OPTIONS_ITEM:
  164.             options = optinteract(options)
  165.     tmp = string.splitfields(GetDialogItemText(h), '\r')
  166.     rv = []
  167.     for i in tmp:
  168.         if i:
  169.             rv.append(i)
  170.     return rv, pythondir, options
  171.     
  172. def getprefpath(id):
  173.     # Load the path and directory resources
  174.     try:
  175.         sr = GetResource('STR#', id)
  176.     except (MacOS.Error, Res.Error):
  177.         return None, None
  178.     d = sr.data
  179.     l = restolist(d)
  180.     return l, sr
  181.  
  182. def getprefdir(id):
  183.     try:
  184.         dr = GetResource('alis', id)
  185.         fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
  186.     except (MacOS.Error, Res.Error):
  187.         return None, None, 1
  188.     return fss, dr, fss_changed
  189.  
  190. def getoptions(id):
  191.     try:
  192.         opr = GetResource('Popt', id)
  193.     except (MacOS.Error, Res.Error):
  194.         return [0]*9, None
  195.     options = map(lambda x: ord(x), opr.data)
  196.     while len(options) < 9:
  197.         options = options + [0]
  198.     return options, opr
  199.     
  200. def getgusioptions(id):
  201.     try:
  202.         opr = GetResource('GU\267I', id)
  203.     except (MacOS.Error, Res.Error):
  204.         return '????', '????', 0, None
  205.     data = opr.data
  206.     type = data[GUSIPOS_TYPE:GUSIPOS_TYPE+4]
  207.     creator = data[GUSIPOS_CREATOR:GUSIPOS_CREATOR+4]
  208.     flags = ord(data[GUSIPOS_FLAGS])
  209.     version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
  210.     if version <> GUSIVERSION:
  211.         message('GU\267I resource version "%s", fixing to "%s"'%(version, GUSIVERSION))
  212.         flags = 0
  213.     delay = (not not (flags & GUSIFLAGS_DELAY))
  214.     return creator, type, delay, opr
  215.     
  216. def setgusioptions(opr, creator, type, delay):
  217.     data = opr.data
  218.     flags = ord(data[GUSIPOS_FLAGS])
  219.     version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
  220.     if version <> GUSIVERSION:
  221.         flags = 0x88
  222.         version = GUSIVERSION
  223.     if delay:
  224.         flags = flags | GUSIFLAGS_DELAY
  225.     else:
  226.         flags = flags & ~GUSIFLAGS_DELAY
  227.     data = type + creator + data[GUSIPOS_SKIP] + chr(flags) + GUSIVERSION + data[GUSIPOS_VERSION+4:]
  228.     return data
  229.     
  230. def openpreffile(rw):
  231.     # Find the preferences folder and our prefs file, create if needed.    
  232.     vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
  233.     try:
  234.         pnhandle = GetNamedResource('STR ', PREFNAME_NAME)
  235.     except Res.Error:
  236.         message("No %s resource (old Python?)"%PREFNAME_NAME)
  237.         sys.exit(1)
  238.     prefname = pnhandle.data[1:]
  239.     preff_fss = macfs.FSSpec((vrefnum, dirid, prefname))
  240.     try:
  241.         preff_handle = FSpOpenResFile(preff_fss, rw)
  242.     except Res.Error:
  243.         # Create it
  244.         message('No preferences file, creating one...')
  245.         FSpCreateResFile(preff_fss, 'Pyth', 'pref', smAllScripts)
  246.         preff_handle = FSpOpenResFile(preff_fss, rw)
  247.     return preff_handle
  248.     
  249. def openapplet(name):
  250.     fss = macfs.FSSpec(name)
  251.     try:
  252.         app_handle = FSpOpenResFile(fss, WRITE)
  253.     except Res.Error:
  254.         message('File does not have a resource fork.')
  255.         sys.exit(0)
  256.     return app_handle
  257.         
  258.     
  259. def edit_preferences():
  260.     preff_handle = openpreffile(WRITE)
  261.     
  262.     l, sr = getprefpath(PATH_STRINGS_ID)
  263.     if l == None:    
  264.         message('Cannot find any sys.path resource! (Old python?)')
  265.         sys.exit(0)
  266.         
  267.     fss, dr, fss_changed = getprefdir(DIRECTORY_ID)
  268.     if fss == None:
  269.         fss = macfs.FSSpec(os.getcwd())
  270.         fss_changed = 1
  271.         
  272.     options, opr = getoptions(OPTIONS_ID)
  273.     saved_options = options[:]
  274.     
  275.     creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
  276.     saved_gusi_options = creator, type, delaycons
  277.     
  278.     # Let the user play away
  279.     result = interact(l, fss, (options, creator, type, delaycons),
  280.              'System-wide preferences')
  281.     
  282.     # See what we have to update, and how
  283.     if result == None:
  284.         sys.exit(0)
  285.         
  286.     pathlist, nfss, (options, creator, type, delaycons) = result
  287.     if nfss != fss:
  288.         fss_changed = 1
  289.         
  290.     if fss_changed:
  291.         alias = nfss.NewAlias()
  292.         if dr:
  293.             dr.data = alias.data
  294.             dr.ChangedResource()
  295.         else:
  296.             dr = Resource(alias.data)
  297.             dr.AddResource('alis', DIRECTORY_ID, '')
  298.             
  299.     if pathlist != l:
  300.         if pathlist == []:
  301.             if sr.HomeResFile() == preff_handle:
  302.                 sr.RemoveResource()
  303.         elif sr.HomeResFile() == preff_handle:
  304.             sr.data = listtores(pathlist)
  305.             sr.ChangedResource()
  306.         else:
  307.             sr = Resource(listtores(pathlist))
  308.             sr.AddResource('STR#', PATH_STRINGS_ID, '')
  309.             
  310.     if options != saved_options:
  311.         newdata = reduce(lambda x, y: x+chr(y), options, '')
  312.         if opr and opr.HomeResFile() == preff_handle:
  313.             opr.data = newdata
  314.             opr.ChangedResource()
  315.         else:
  316.             opr = Resource(newdata)
  317.             opr.AddResource('Popt', OPTIONS_ID, '')
  318.             
  319.     if (creator, type, delaycons) != saved_gusi_options:
  320.         newdata = setgusioptions(gusi_opr, creator, type, delaycons)
  321.         if gusi_opr.HomeResFile() == preff_handle:
  322.             gusi_opr.data = newdata
  323.             gusi_opr.ChangedResource()
  324.         else:
  325.             ngusi_opr = Resource(newdata)
  326.             ngusi_opr.AddResource('GU\267I', GUSI_ID, '')
  327.                 
  328.     CloseResFile(preff_handle)
  329.     
  330. def edit_applet(name):
  331.     pref_handle = openpreffile(READ)
  332.     app_handle = openapplet(name)
  333.     
  334.     notfound = ''
  335.     l, sr = getprefpath(OVERRIDE_PATH_STRINGS_ID)
  336.     if l == None:
  337.         notfound = 'path'
  338.         
  339.         l, dummy = getprefpath(PATH_STRINGS_ID)
  340.         if l == None:    
  341.             message('Cannot find any sys.path resource! (Old python?)')
  342.             sys.exit(0)
  343.         
  344.     fss, dr, fss_changed = getprefdir(OVERRIDE_DIRECTORY_ID)
  345.     if fss == None:
  346.         if notfound:
  347.             notfound = notfound + ', directory'
  348.         else:
  349.             notfound = 'directory'
  350.         fss, dummy, dummy2 = getprefdir(DIRECTORY_ID)
  351.         if fss == None:
  352.             fss = macfs.FSSpec(os.getcwd())
  353.             fss_changed = 1
  354.  
  355.     options, opr = getoptions(OVERRIDE_OPTIONS_ID)
  356.     if not opr:
  357.         if notfound:
  358.             notfound = notfound + ', options'
  359.         else:
  360.             notfound = 'options'
  361.         options, dummy = getoptions(OPTIONS_ID)
  362.     saved_options = options[:]
  363.     
  364.     creator, type, delaycons, gusi_opr = getgusioptions(OVERRIDE_GUSI_ID)
  365.     if not gusi_opr:
  366.         if notfound:
  367.             notfound = notfound + ', GUSI options'
  368.         else:
  369.             notfound = 'GUSI options'
  370.         creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
  371.     saved_gusi_options = creator, type, delaycons
  372.     
  373.     dummy = dummy2 = None # Discard them.
  374.     
  375.     if notfound:
  376.         message('Warning: initial %s taken from system-wide defaults'%notfound)
  377.     # Let the user play away
  378.     print 'DBG interaction'
  379.     result = interact(l, fss, (options, creator, type, delaycons), name)
  380.     
  381.     # See what we have to update, and how
  382.     if result == None:
  383.         sys.exit(0)
  384.         
  385.     pathlist, nfss, (options, creator, type, delaycons) = result
  386.     if nfss != fss:
  387.         fss_changed = 1
  388.         
  389.     if fss_changed:
  390.         alias = nfss.NewAlias()
  391.         if dr:
  392.             dr.data = alias.data
  393.             dr.ChangedResource()
  394.         else:
  395.             dr = Resource(alias.data)
  396.             dr.AddResource('alis', OVERRIDE_DIRECTORY_ID, '')
  397.             
  398.     if pathlist != l:
  399.         if pathlist == []:
  400.             if sr.HomeResFile() == app_handle:
  401.                 sr.RemoveResource()
  402.         elif sr and sr.HomeResFile() == app_handle:
  403.             sr.data = listtores(pathlist)
  404.             sr.ChangedResource()
  405.         else:
  406.             sr = Resource(listtores(pathlist))
  407.             sr.AddResource('STR#', OVERRIDE_PATH_STRINGS_ID, '')
  408.             
  409.     if options != saved_options:
  410.         newdata = reduce(lambda x, y: x+chr(y), options, '')
  411.         if opr and opr.HomeResFile() == app_handle:
  412.             opr.data = newdata
  413.             opr.ChangedResource()
  414.         else:
  415.             opr = Resource(newdata)
  416.             opr.AddResource('Popt', OVERRIDE_OPTIONS_ID, '')
  417.             
  418.     if (creator, type, delaycons) != saved_gusi_options:
  419.         newdata = setgusioptions(gusi_opr, creator, type, delaycons)
  420.         id, type, name = gusi_opr.GetResInfo()
  421.         if gusi_opr.HomeResFile() == app_handle and id == OVERRIDE_GUSI_ID:
  422.             gusi_opr.data = newdata
  423.             gusi_opr.ChangedResource()
  424.         else:
  425.             ngusi_opr = Resource(newdata)
  426.             ngusi_opr.AddResource('GU\267I', OVERRIDE_GUSI_ID, '')
  427.             
  428.     CloseResFile(app_handle)
  429.  
  430. def main():
  431.     try:
  432.         h = OpenResFile('EditPythonPrefs.rsrc')
  433.     except Res.Error:
  434.         pass    # Assume we already have acces to our own resource
  435.     
  436.     if len(sys.argv) <= 1:
  437.         edit_preferences()
  438.     else:
  439.         for appl in sys.argv[1:]:
  440.             edit_applet(appl)
  441.         
  442.  
  443. if __name__ == '__main__':
  444.     main()
  445.